﻿#region License
/*
 * Microsoft Public License (Ms-PL)
 * 
 * This license governs use of the accompanying software. If you use the software, you accept this license. 
 * If you do not accept the license, do not use the software.
 *
 * 1. Definitions
 *
 * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
 *
 * A "contribution" is the original software, or any additions or changes to the software.
 *
 * A "contributor" is any person that distributes its contribution under this license.
 *
 * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
 *
 * 2. Grant of Rights
 *
 * (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, 
 * each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, 
 * prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
 *
 * (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, 
 * each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, 
 * use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the 
 * contribution in the software.
 *
 * 3. Conditions and Limitations
 *
 * (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
 *
 * (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, 
 * your patent license from such contributor to the software ends automatically.
 *
 * (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, 
 * and attribution notices that are present in the software.
 *
 * (D) If you distribute any portion of the software in source code form, you may do so only under this license by including 
 * a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, 
 * you may only do so under a license that complies with this license.
 *
 * (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. 
 * You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, 
 * the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 
 */
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace ROL.Core.Utils
{
    public class Utilities
    {
        XmlDocument xmlConfig = new XmlDocument();

        public Utilities()
        {
        }


        /// <summary>
        /// Wrapper for writing to the console.
        /// </summary>
        /// <param name="logAsColor"></param>
        /// <param name="logAsMsg"></param>
        /// <param name="msgColor"></param>
        /// <param name="msg"></param>
        public void WriteLine(ConsoleColor logAsColor, string logAsMsg, ConsoleColor msgColor, string msg)
        {
            Console.ForegroundColor = logAsColor;
            Console.Write(logAsMsg);
            Console.ForegroundColor = msgColor;
            Console.Write(msg + "\n");
            Console.ResetColor();

        }




        public string ServerMessage()
        {
            StringBuilder msg = new StringBuilder();
            msg.AppendLine("ROL (Realm OffLine) copyright 2012 by the ROL Development Team.");
            msg.AppendLine("We are using Microsoft Public License (Ms-PL)");
            msg.AppendLine("Project is in Alpha and we have need for packet programmers.");
            msg.AppendLine("\n");
            msg.AppendLine("http://realmserveroffline.codeplex.com/");

            return msg.ToString();
        }



        public byte[] RouteToPatchServer()
        {
            // Here we read the patch server information and send it to the client
            // 16 unchangeable bytes then the length of our ip address
            // The the ip address next the length of the port and then the port address
            // Then we add 6 to that for a unchangeable trailer and we have our size.
            int fullPacketLength = 40;//16 + GetPatchServerIPFromConfigByte().Length + 8;

            byte[] fullHeader = { (byte)fullPacketLength, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0 }; //8 bytes then 16 (+16) bytes we have to count

            byte[] patchServer = GetPatchServerIPFromConfigByte();//{ 8, 0, 49, 48, 46, 48, 46, 48, 46, 56, 4, 0, 54, 48, 48, 53 }; // See function below.

            byte[] fullTrailer = { 0, 0, 112, 2, 0, 52, 50, 12 }; //Dont need to change this.

            // Combine all the byte arrays into one
            byte[] reply = Combine(fullHeader, patchServer, fullTrailer);


            return reply;

        }

        /// <summary>
        /// Sends back the alterd packet with our server list. 
        /// </summary>
        /// <returns></returns>
        public byte[] GameServerListReply()
        {
            //Change the 0x74 thats our packet size
            byte[] header = { /*Length total to change*/0x4b,/**/ 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                              0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  }; //16 bytes added
            // Our list goes here
            byte[] livereply = { 0x02, 0x10, 0x00, 0x44, 0x65, 0x73, 0x70, 0x6f, 0x74, 0x68, 0x65, 0x73, 0x27, 0x20, 0x47, 0x72, 
                                 0x6f, 0x76, 0x65, 0x02, 0x00, /*UP*/0x75, 0x70, /*UP*/0x02, 0x00, 0x38, 0x32, 0x0c, 0x00, /*IP*/0x36, 0x35, 0x2e, 
                                 0x31, 0x38, 0x33, 0x2e, 0x31, 0x37, 0x33, 0x2e, 0x32, 0x04, 0x00, 0x38, 0x30, 0x30, 0x31 }; // 92
            //byte[] testreply = { 0x02, 0x11, 0x00, 0x54, 0x68, 0x65, 0x20, 0x52, 0x65, 0x61, 0x6c, 0x6d, 0x20, 0x4f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65,
              //                   0x02, 0x00, 0x75, 0x70, 0x01, 0x00, 0x0, 0x0, 0x36, 0x35, 0x2e, 0x31, 0x38, 0x33, 0x2e, 0x31, 0x37, 0x33, 0x2e, 0x32,
                //                 0x38, 0x30, 0x30, 0x31}; // 44
            byte[] testreply = { 0x02, 0x18, 0x00, 0x54, 0x68, 0x65, 0x20, 0x52, 0x65, 0x61, 0x6c, 0x6d, 0x20, 0x4f, 0x46, 0x46, 0x4c, 0x69, 0x6e, 
                                   0x65, 0x28, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x29, /*ServerName End (27 Length)*/ 
                                   0x02, 0x00, 0x75, 0x70, /*End Status of server (up) (down) this is Alpha (4 Length)*/
                                   0x02, 0x00, /*This is just 1 player*/0x31, 0x00, /*End Players Online, this is 65535 (4) Length*/
                                   0x08, 0x00, 0x31, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x38, /*End of IP Address (10 Length)*/
                                   0x04, 0x00, 0x37, 0x30, 0x30 ,0x32/*End of Port full server info for 1 server (6) Length*/ };  // 65 bytes 0x41 hex

            byte[] trailer = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00}; //8 bytes added

            byte[] reply = Combine(header, testreply, trailer);

            return reply;
        }





        #region Xml Data Convertors
        
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string GetRouterIPFromConfig()
        {
            
            xmlConfig.Load("Config.xml");

            XmlNode router = xmlConfig.SelectSingleNode("Config/RouterIP/text()");
            string ip = router.Value;
            return ip;
            
        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public int GetPatchServerPortFromConfig()
        {

            xmlConfig.Load("Config.xml");

            XmlNode port = xmlConfig.SelectSingleNode("Config/PatchServerPort/text()");
            int p = Int32.Parse(port.Value); 
            return p;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string GetPatchServerIPFromConfig()
        {

            xmlConfig.Load("Config.xml");

            XmlNode Ip = xmlConfig.SelectSingleNode("Config/PatchServerIP/text()");
            string ip = Ip.Value;
            return ip;

        }
        /// <summary>
        /// Converts the ip and port for the patch server
        /// into its byte array counterpart
        /// </summary>
        /// <returns></returns>
        public byte[] GetPatchServerIPFromConfigByte()
        {

            List<byte> replyList = new List<byte>();
            System.Text.Encoding enc = System.Text.Encoding.ASCII;
            XmlDocument xmlConfig = new XmlDocument();
            xmlConfig.Load("Config.xml");



            //Grab the ip
            XmlNode serverIP = xmlConfig.SelectSingleNode("Config/PatchServerIP/text()");
            string ip = serverIP.Value;
            byte[] k = enc.GetBytes(ip);
            byte[] p = enc.GetBytes(k.Length.ToString("X"));

            if (k.Length <= 15) // if our length is under 15 then we have to add a blank byte after it
            {
                replyList.Add((byte)k.Length);
                replyList.Add(0);
            }
            else
            {
                replyList.AddRange(p);
            }
            replyList.AddRange(k);
            // Port
            XmlNode portNumber = xmlConfig.SelectSingleNode("Config/PatchServerPort/text()");
            string _port = portNumber.Value;
            byte[] v = enc.GetBytes(_port);
            byte[] z = enc.GetBytes(v.Length.ToString());

            if (v.Length <= 15)
            {
                replyList.Add((byte)v.Length);
                replyList.Add(0);
            }
            else
            {
                replyList.AddRange(z);
            }
            replyList.AddRange(v);
            return replyList.ToArray();
        }
        #endregion Xml Data Convertors

        #region Byte array Merge tools

        /// <summary>
        /// Combines 2 byte arrays into 1
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public byte[] Combine(byte[] a, byte[] b)
        {
            byte[] c = new byte[a.Length + b.Length];
            System.Buffer.BlockCopy(a, 0, c, 0, a.Length);
            System.Buffer.BlockCopy(b, 0, c, a.Length, b.Length);
            return c;
        }

        /// <summary>
        /// Combines 3 byte arrays into 1
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        public byte[] Combine(byte[] a, byte[] b, byte[] c)
        {
            byte[] j = new byte[a.Length + b.Length + c.Length];
            System.Buffer.BlockCopy(a, 0, j, 0, a.Length);
            System.Buffer.BlockCopy(b, 0, j, a.Length, b.Length);
            System.Buffer.BlockCopy(c, 0, j, a.Length + b.Length, c.Length);
            return j;
        }

        /// <summary>
        /// Combines 4 byte arrays into 1
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        public byte[] Combine(byte[] a, byte[] b, byte[] c, byte[] d)
        {
            byte[] j = new byte[a.Length + b.Length + c.Length + d.Length];
            System.Buffer.BlockCopy(a, 0, j, 0, a.Length);
            System.Buffer.BlockCopy(b, 0, j, a.Length, b.Length);
            System.Buffer.BlockCopy(c, 0, j, a.Length + b.Length, c.Length);
            System.Buffer.BlockCopy(d, 0, j, a.Length + b.Length + c.Length, d.Length);
            return j;
        }

        /// <summary>
        /// Combine 5 byte arays into 1
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public byte[] Combine(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e)
        {
            byte[] j = new byte[a.Length + b.Length + c.Length + d.Length + e.Length];
            System.Buffer.BlockCopy(a, 0, j, 0, a.Length);
            System.Buffer.BlockCopy(b, 0, j, a.Length, b.Length);
            System.Buffer.BlockCopy(c, 0, j, a.Length + b.Length, c.Length);
            System.Buffer.BlockCopy(d, 0, j, a.Length + b.Length + c.Length, d.Length);
            System.Buffer.BlockCopy(e, 0, j, a.Length + b.Length + c.Length + d.Length, e.Length);
            return j;
        }

        /// <summary>
        /// Combine 6 byte arrays into 1
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>
        /// <param name="e"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public byte[] Combine(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, byte[] f)
        {
            byte[] j = new byte[a.Length + b.Length + c.Length + d.Length + e.Length + f.Length];
            System.Buffer.BlockCopy(a, 0, j, 0, a.Length);
            System.Buffer.BlockCopy(b, 0, j, a.Length, b.Length);
            System.Buffer.BlockCopy(c, 0, j, a.Length + b.Length, c.Length);
            System.Buffer.BlockCopy(d, 0, j, a.Length + b.Length + c.Length, d.Length);
            System.Buffer.BlockCopy(e, 0, j, a.Length + b.Length + c.Length + d.Length, e.Length);
            System.Buffer.BlockCopy(f, 0, j, a.Length + b.Length + c.Length + d.Length + e.Length, f.Length);
            return j;
        }

        /// <summary>
        /// Combine 7 byte arrays into 1
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>
        /// <param name="e"></param>
        /// <param name="f"></param>
        /// <param name="g"></param>
        /// <returns></returns>
        public byte[] Combine(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, byte[] f, byte[] g)
        {
            byte[] j = new byte[a.Length + b.Length + c.Length + d.Length + e.Length + f.Length + g.Length];
            System.Buffer.BlockCopy(a, 0, j, 0, a.Length);
            System.Buffer.BlockCopy(b, 0, j, a.Length, b.Length);
            System.Buffer.BlockCopy(c, 0, j, a.Length + b.Length, c.Length);
            System.Buffer.BlockCopy(d, 0, j, a.Length + b.Length + c.Length, d.Length);
            System.Buffer.BlockCopy(e, 0, j, a.Length + b.Length + c.Length + d.Length, e.Length);
            System.Buffer.BlockCopy(f, 0, j, a.Length + b.Length + c.Length + d.Length + e.Length, f.Length);
            System.Buffer.BlockCopy(g, 0, j, a.Length + b.Length + c.Length + d.Length + e.Length + f.Length, g.Length);
            return j;
        }
        #endregion Byte array Merge tools



        public byte[] ParseHex(byte[] hex)
        {
            byte[] result = new byte[hex.Length / 2];
            int hexIndex = 0;
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = (byte)(ParseHexDigit(hex[hexIndex++]) * 16 +
                ParseHexDigit(hex[hexIndex++]));

            }
            return result;
        }

        private int ParseHexDigit(byte c)
        {
            if (c >= '0' && c <= '9')
            {
                return c - '0';
            }
            if (c >= 'a' && c <= 'f')
            {
                return c - 'a' + 10;
            }
            if (c >= 'A' && c <= 'F')
            {
                return c - 'A' + 10;
            }
            throw new ArgumentException("Invalid hex character");
        }

    }
}
